Added support for parsing required toolkit versions (so that ui
authorTristan Van Berkom <tvb@src.gnome.org>
Sun, 25 May 2008 15:12:39 +0000 (15:12 +0000)
committerTristan Van Berkom <tvb@src.gnome.org>
Sun, 25 May 2008 15:12:39 +0000 (15:12 +0000)
* gtk/gtkbuilderprivate.h, gtk/gtkbuilder.h, gtk/gtkbuilderparser.c:
Added support for parsing required toolkit versions (so that ui descriptions
can target specific versions of the backend widget libraries) bug 527612.

* gtk/docs/reference/gtk/tmpl/gtkbuilder.sgml: Added documentation
for the added xml tags to the ui description.

svn path=/trunk/; revision=20152

ChangeLog
docs/reference/gtk/tmpl/gtkbuilder.sgml
gtk/gtkbuilder.h
gtk/gtkbuilderparser.c
gtk/gtkbuilderprivate.h

index d1522ee64d7a0a1ed596edc73531ac3530004909..c85d6b4cc6859f0ab4d7628eaf2ffcbe96a79034 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2008-05-25  Tristan Van Berkom <tvb@gnome.org>
+
+       * gtk/gtkbuilderprivate.h, gtk/gtkbuilder.h, gtk/gtkbuilderparser.c:
+       Added support for parsing required toolkit versions (so that ui descriptions
+       can target specific versions of the backend widget libraries) bug 527612.
+
+       * gtk/docs/reference/gtk/tmpl/gtkbuilder.sgml: Added documentation
+       for the added xml tags to the ui description.
+
 2008-05-25  Richard Hult  <richard@imendio.com>
 
        * gtk/gtkdnd-quartz.c: (gtk_drag_drop_finished): Run
index 0677fc158f03154f7560e0c71515bbece65623e4..f1e19a69e00729e05c9015d763ead9c3701ea3d3 100644 (file)
@@ -50,10 +50,11 @@ which are more limited in scope.
 </para>
 <para>
 <programlisting><![CDATA[
-<!ELEMENT interface object* >
+<!ELEMENT interface (requires|object)* >
 <!ELEMENT object    (property|signal|child|ANY)* >
 <!ELEMENT property  PCDATA >
 <!ELEMENT signal    EMPTY >
+<!ELEMENT requires  EMPTY >
 <!ELEMENT child     (object|ANY*) >
 
 <!ATTLIST interface  domain                #IMPLIED >
@@ -61,6 +62,8 @@ which are more limited in scope.
                      class                 #REQUIRED
                      type-func             #IMPLIED
                      constructor           #IMPLIED >
+<!ATTLIST requires   lib                   #REQUIRED
+                     version               #REQUIRED >
 <!ATTLIST property   name                  #REQUIRED
                      translatable          #IMPLIED 
                      comments               #IMPLIED
@@ -88,6 +91,11 @@ elements, which describe child objects (most often widgets
 inside a container, but also e.g. actions in an action group,
 or columns in a tree model). A &lt;child&gt; element contains
 an &lt;object&gt; element which describes the child object.
+The target toolkit version(s) are described by &lt;requires&gt;
+elements, the "lib" attribute specifies the widget library in
+question (currently the only supported value is "gtk+") and the "version" 
+attribute specifies the target version in the form "&lt;major&gt;.&lt;minor&gt;".
+The builder will error out if the version requirements are not met.
 </para>
 <para>
 Typically, the specific kind of object represented by an
@@ -258,6 +266,7 @@ respective objects, see
 
 </para>
 
+@GTK_BUILDER_ERROR_VERSION_MISMATCH: 
 @GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION: 
 @GTK_BUILDER_ERROR_UNHANDLED_TAG: 
 @GTK_BUILDER_ERROR_MISSING_ATTRIBUTE: 
index 732acaa15e9b9f95cb49d3693abe96e46ac7400e..eb82a61f7fd106a1aaaf0d4f1146164273eb22b0 100644 (file)
@@ -39,6 +39,7 @@ typedef struct _GtkBuilderPrivate GtkBuilderPrivate;
 
 typedef enum
 {
+  GTK_BUILDER_ERROR_VERSION_MISMATCH,
   GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION,
   GTK_BUILDER_ERROR_UNHANDLED_TAG,
   GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
index 15fbae3a3dbc0c24ffdfe8da01b0d4e10412073a..33b4f1bd88da7cdf0c5048e84953bef38abd05c1 100644 (file)
@@ -28,6 +28,7 @@
 #include "gtkbuilder.h"
 #include "gtkbuildable.h"
 #include "gtkdebug.h"
+#include "gtkversion.h"
 #include "gtktypeutils.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
@@ -224,6 +225,63 @@ _get_type_by_symbol (const gchar* symbol)
   return g_strdup (g_type_name (type));
 }
 
+static void
+parse_requires (ParserData   *data,
+               const gchar  *element_name,
+               const gchar **names,
+               const gchar **values,
+               GError      **error)
+{
+  RequiresInfo *req_info;
+  const gchar  *library = NULL;
+  const gchar  *version = NULL;
+  gchar       **split;
+  gint          i, version_major = 0, version_minor = 0;
+  gint          line_number, char_number;
+
+  g_markup_parse_context_get_position (data->ctx,
+                                       &line_number,
+                                       &char_number);
+
+  for (i = 0; names[i] != NULL; i++)
+    {
+      if (strcmp (names[i], "lib") == 0)
+        library = values[i];
+      else if (strcmp (names[i], "version") == 0)
+       version = values[i];
+      else
+       error_invalid_attribute (data, element_name, names[i], error);
+    }
+
+  if (!library || !version)
+    {
+      error_missing_attribute (data, element_name, 
+                              version ? "lib" : "version", error);
+      return;
+    }
+
+  if (!(split = g_strsplit (version, ".", 2)) || !split[0] || !split[1])
+    {
+      g_set_error (error,
+                  GTK_BUILDER_ERROR,
+                  GTK_BUILDER_ERROR_INVALID_VALUE,
+                  "%s:%d:%d <%s> attribute has malformed value \"%s\"",
+                  data->filename,
+                  line_number, char_number, "version", version);
+      return;
+    }
+  version_major = g_ascii_strtoll (split[0], NULL, 10);
+  version_minor = g_ascii_strtoll (split[1], NULL, 10);
+  g_strfreev (split);
+
+  req_info = g_slice_new0 (RequiresInfo);
+  req_info->library = g_strdup (library);
+  req_info->major   = version_major;
+  req_info->minor   = version_minor;
+  state_push (data, req_info);
+  req_info->tag.name = element_name;
+}
+
 static void
 parse_object (ParserData   *data,
               const gchar  *element_name,
@@ -521,6 +579,14 @@ _free_signal_info (SignalInfo *info,
   g_slice_free (SignalInfo, info);
 }
 
+void
+_free_requires_info (RequiresInfo *info,
+                    gpointer user_data)
+{
+  g_free (info->library);
+  g_slice_free (RequiresInfo, info);
+}
+
 static void
 parse_interface (ParserData   *data,
                 const gchar  *element_name,
@@ -729,8 +795,10 @@ start_element (GMarkupParseContext *context,
     if (!subparser_start (context, element_name, names, values,
                          data, error))
       return;
-  
-  if (strcmp (element_name, "object") == 0)
+
+  if (strcmp (element_name, "requires") == 0)
+    parse_requires (data, element_name, names, values, error);
+  else if (strcmp (element_name, "object") == 0)
     parse_object (data, element_name, names, values, error);
   else if (strcmp (element_name, "child") == 0)
     parse_child (data, element_name, names, values, error);
@@ -821,7 +889,27 @@ end_element (GMarkupParseContext *context,
       return;
     }
 
-  if (strcmp (element_name, "object") == 0)
+  if (strcmp (element_name, "requires") == 0)
+    {
+      RequiresInfo *req_info = state_pop_info (data, RequiresInfo);
+
+      /* TODO: Allow third party widget developers to check thier
+       * required versions, possibly throw a signal allowing them
+       * to check thier library versions here.
+       */
+      if (!strcmp (req_info->library, "gtk+"))
+       {
+         if (!GTK_CHECK_VERSION (req_info->major, req_info->minor, 0))
+           g_set_error (error,
+                        GTK_BUILDER_ERROR,
+                        GTK_BUILDER_ERROR_VERSION_MISMATCH,
+                        "%s: required %s version %d.%d, current version is %d.%d",
+                        data->filename, req_info->library, 
+                        req_info->major, req_info->minor,
+                        GTK_MAJOR_VERSION, GTK_MINOR_VERSION);
+       }
+    }
+  else if (strcmp (element_name, "object") == 0)
     {
       ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
       ChildInfo* child_info = state_peek_info (data, ChildInfo);
@@ -948,6 +1036,8 @@ free_info (CommonInfo *info)
     free_property_info ((PropertyInfo *)info);
   else if (strcmp (info->tag.name, "signal") == 0) 
     _free_signal_info ((SignalInfo *)info, NULL);
+  else if (strcmp (info->tag.name, "requires") == 0) 
+    _free_requires_info ((RequiresInfo *)info, NULL);
   else 
     g_assert_not_reached ();
 }
index a1d9eb41e3541886d2ac5e86fe068b89fea20b60..ded6f238bea3e20ef824fc14c92a241210fc4382 100644 (file)
@@ -71,6 +71,13 @@ typedef struct {
   gchar *connect_object_name;
 } SignalInfo;
 
+typedef struct {
+  TagInfo  tag;
+  gchar   *library;
+  gint     major;
+  gint     minor;
+} RequiresInfo;
+
 typedef struct {
   GMarkupParser *parser;
   gchar *tagname;